package com.marquisx.tzdice;

import java.util.ArrayList;
import java.util.List;

import android.app.Activity;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.media.AudioManager;
import android.os.Bundle;
import android.speech.RecognizerIntent;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup.LayoutParams;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.EditText;
import android.widget.ImageButton;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.ListView;
import android.widget.ScrollView;
import android.widget.TableLayout;
import android.widget.TextView;
import android.widget.Toast;

import com.marquisx.common.sensor.AccelerometerListener;
import com.marquisx.common.sensor.AccelerometerManager;
import com.marquisx.common.ui.dialog.AmbilWarnaDialog;
import com.marquisx.common.ui.dialog.NumberKeypad;
import com.marquisx.common.utils.StringUtils;
import com.marquisx.common.utils.TZUtils;
import com.marquisx.common.utils.TimeUtils;
import com.marquisx.tzdice.Constants.RecordType;
import com.marquisx.tzdice.model.DiceAction;
import com.marquisx.tzdice.model.DiceActionManager;
import com.marquisx.tzdice.model.DiceRecord;

public class TZDice extends Activity implements OnClickListener, OnLongClickListener, AccelerometerListener
{
	private static final String TAG = "TZDice:main";

	private DiceActionManager actionManager;

	private DiceRecordAdapter recordAdapter;

	private DiceAction currentAction = new DiceAction();
	private DiceRecord currentRecord = new DiceRecord(RecordType.Roll);
	private StringBuffer logBuffer = new StringBuffer();
	private String currentLocale = "";
	private boolean isLocaleChanged = false;
	
	private LinearLayout basicContainer;
	private LinearLayout backgroundImageContainer;
	private LinearLayout offsetContainer;
	private LinearLayout timesContainer;
	private ScrollView actionListContainer;
	private LinearLayout actionListLayout;
	private LinearLayout sayContainer;
	private LinearLayout rollContainer;
	
	private TableLayout diceTable;
	
	private ListView recordLV;

	private ImageView d4IView;
	private ImageView d6IView;
	private ImageView d8IView;
	private ImageView d10IView;
	private ImageView d12IView;
	private ImageView d20IView;
	private ImageView d100IView;
	
	private ImageView micIView;

	private Button rollBtn;
//	private Button clearBtn;
	//private Button sayBtn;
	private ImageButton speakBtn;
	
	private EditText sayET;

	private ImageButton diceIBtn;
	private ImageButton actionIBtn;
	private ImageButton offsetIBtn;
	private ImageButton timesIBtn;
	private ImageButton clearIBtn;
	private ImageButton shakeCtrlIBtn;
	private ImageButton userProfileIBtn;
	private ImageButton logIBtn;

	private ImageButton offsetPlusIBtn;
	private ImageButton offsetMinusIBtn;
	private ImageButton timesPlusIBtn;
	private ImageButton timesMinusIBtn;

	private TextView offsetResultView;
	private TextView timesResultView;
	private TextView statusView;

	/** Called when the activity is first created. */
	@Override
	public void onCreate(Bundle savedInstanceState)
	{
		super.onCreate(savedInstanceState);
		Log.v(TAG, "onCreate");
		
		TZUtils.changeLocale(this, Setting.getLocal(this));
		
		actionManager = DiceActionManager.getInstance(this);
		
		setContentView(R.layout.main);
		setVolumeControlStream(AudioManager.STREAM_MUSIC);

		findViews();
		prepareViews();
		setListeners();
	}
	
	@Override
	public void onPause()
	{
		super.onPause();
		AccelerometerManager.stopListening();
	}

	@Override
	public void onResume()
	{
		super.onResume();
		
		AccelerometerManager.configure(
				Setting.getShakeSensitivity(this), 
				TimeUtils.SECOND_OF_NANO);
		//restart the listening
		AccelerometerManager.startListening(this, this);
		
		addDiceActionToLayout();
		
		if( !currentLocale.equals(Setting.getLocal(this)) )
		{
			currentLocale = Setting.getLocal(this);
			this.onCreate(null);
			isLocaleChanged = true;
		}
		else
		{
			isLocaleChanged = false;
		}
		
		int currentUserProfilePicId = Setting.getUserProfilePicId(this);
		
		if( currentRecord.getUserProfileId() != currentUserProfilePicId)
		{
			currentRecord.setUserProfileId(currentUserProfilePicId);
		}
		
		int currentBGColor = Setting.getBackgroundColor(this);
		//TODO get old bg color?
		if( true )
		{
			basicContainer.setBackgroundColor(currentBGColor);
		}
		
		int currentBGPicId = Setting.getBackgroundPictureId(this);
		//TODO get old bg pic id?
		if( true )
		{
			backgroundImageContainer.setBackgroundResource(currentBGPicId);
			if( null != backgroundImageContainer.getBackground() )
			{
				backgroundImageContainer.getBackground().setAlpha(Constants.ALPHA_BG_PIC);
			}
		}
		
		refresh();
	}
	
	@Override
	public void onDestroy()
	{
		super.onDestroy();
		
		if(AccelerometerManager.isListening())
		{
			AccelerometerManager.stopListening();
		}
		
		actionManager.closeDB();
	}

	@Override
	public boolean onCreateOptionsMenu(Menu menu)
	{
		super.onCreateOptionsMenu(menu);
		getMenuInflater().inflate(R.menu.menu, menu);
		return true;
	}
	
	@Override
	public boolean onPrepareOptionsMenu(Menu menu)
	{
		super.onPrepareOptionsMenu(menu);
		//if( isLocaleChanged )
		//{
			menu.clear();
			getMenuInflater().inflate(R.menu.menu, menu);
		//}
		return true;
	}

	@Override
	public boolean onOptionsItemSelected(MenuItem item)
	{
		/*
		return MenuManager.onOptionsItemSelected(this, item);
		*/
		switch (item.getItemId())
		{
			case R.id.menu_setting:
				startActivity(new Intent(this, Setting.class));
				return true;
			case R.id.menu_about:
				startActivity(new Intent(this, About.class));
				return true;
			case R.id.menu_help:
				startActivity(new Intent(this, Help.class));
				return true;
			case R.id.menu_exit:
				finish();
				return true;
		}
		return false;
	}

	public void refresh()
	{
		selectDice(currentAction.getDice());
		String currentName = Setting.getUsername(this);
		
		if( Setting.getShake(this))
		{
			shakeCtrlIBtn.setImageResource(R.drawable.shake_on);
		}
		else
		{
			shakeCtrlIBtn.setImageResource(R.drawable.shake_off);
		}
		
		if (!StringUtils.isEmpty(currentName) || !currentName.equals(currentRecord.getUsername()))
		{
			currentRecord.setUsername(currentName);
		}
		
		recordAdapter.refresh();
		updateStatus();
	}

	private void findViews()
	{
		basicContainer = (LinearLayout) findViewById(R.id.basic_container);
		backgroundImageContainer = (LinearLayout) findViewById(R.id.background_image_container);
		timesContainer = (LinearLayout) findViewById(R.id.times_container);
		offsetContainer = (LinearLayout) findViewById(R.id.offset_container);
		actionListContainer = (ScrollView)findViewById(R.id.action_list_container);
		actionListLayout = (LinearLayout) findViewById(R.id.action_list_layout);
		sayContainer = (LinearLayout) findViewById(R.id.say_container);
		rollContainer = (LinearLayout) findViewById(R.id.roll_container);
		
		diceTable = (TableLayout) findViewById(R.id.dice_table);
		
		recordLV = (ListView) findViewById(R.id.record);

		rollBtn = (Button) findViewById(R.id.roll_btn);
		//clearBtn = (Button) findViewById(R.id.clear_btn);
		//sayBtn = (Button) findViewById(R.id.say_btn);
		speakBtn = (ImageButton) findViewById(R.id.speak_btn);
		
		sayET = (EditText) findViewById(R.id.say_et);

		actionIBtn = (ImageButton) findViewById(R.id.action_btn);
		offsetIBtn = (ImageButton) findViewById(R.id.action_offset_btn);
		timesIBtn = (ImageButton) findViewById(R.id.times_btn);
		clearIBtn = (ImageButton) findViewById(R.id.clear_btn);
		diceIBtn = (ImageButton) findViewById(R.id.dice_btn);
		shakeCtrlIBtn = (ImageButton) findViewById(R.id.shake_control_btn);
		userProfileIBtn = (ImageButton) findViewById(R.id.user_profile_btn);
		logIBtn = (ImageButton) findViewById(R.id.log_btn);
		
		offsetPlusIBtn = (ImageButton) findViewById(R.id.offset_plus_btn);
		offsetMinusIBtn = (ImageButton) findViewById(R.id.offset_minus_btn);
		timesPlusIBtn = (ImageButton) findViewById(R.id.times_plus_btn);
		timesMinusIBtn = (ImageButton) findViewById(R.id.times_minus_btn);

		//resultLogView = (EditText) findViewById(R.id.result);
		offsetResultView = (TextView) findViewById(R.id.offset_result);
		timesResultView = (TextView) findViewById(R.id.times_result);
		statusView = (TextView) findViewById(R.id.status_bar);

		d4IView = (ImageView) findViewById(R.id.d4_iv);
		d6IView = (ImageView) findViewById(R.id.d6_iv);
		d8IView = (ImageView) findViewById(R.id.d8_iv);
		d10IView = (ImageView) findViewById(R.id.d10_iv);
		d12IView = (ImageView) findViewById(R.id.d12_iv);
		d20IView = (ImageView) findViewById(R.id.d20_iv);
		d100IView = (ImageView) findViewById(R.id.d100_iv);
		
		micIView = (ImageView) findViewById(R.id.voice_img);
	}

	private void prepareViews()
	{
		currentLocale = Setting.getLocal(this);
		basicContainer.setBackgroundColor(Setting.getBackgroundColor(this));
		
		backgroundImageContainer.getBackground().setAlpha(Constants.ALPHA_BG_PIC);
		this.setTitle(getText(R.string.app_name) + " " + getText(R.string.app_version_name));

		offsetContainer.setVisibility(LinearLayout.GONE);
		timesContainer.setVisibility(LinearLayout.GONE);
		actionListContainer.setVisibility(LinearLayout.GONE);
		
		currentAction.setDice(Setting.getDefaultDice(this));
		selectDice(currentAction.getDice());
		
		currentRecord.setUsername(Setting.getUsername(this));
		currentRecord.setUserProfileId(Constants.USE_RPROFILE_PIC_ID_DEF);
		
		//actionIBtn.setAlpha(Constants.ALPHA_UNSELECTED);
		actionIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		offsetIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		timesIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		clearIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		diceIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		shakeCtrlIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		userProfileIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		logIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		
		rollBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		
		//offsetPlusIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		//offsetMinusIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		//timesPlusIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		//timesMinusIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
		
		prepareRecordListView();
		addDiceActionToLayout();
		
		refresh();
	}
	
	private void prepareRecordListView()
	{
		// Set up dice record adapter
		recordAdapter = new DiceRecordAdapter(this);
		recordLV.setAdapter(recordAdapter);
	}
	
	private void addDiceActionToLayout()
	{
		actionListLayout.removeAllViews();
		
		for( final DiceAction diceAction : actionManager.getActionList() )
		{
			ImageButton diceActionIBtn = new ImageButton(this);
			diceActionIBtn.setImageResource(diceAction.getPictureId());
			diceActionIBtn.setLayoutParams(new LayoutParams(LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT));
			//diceActionIBtn.getBackground().setAlpha(Constants.ALPHA_SEMITRANSPARENT);
			
			diceActionIBtn.setOnClickListener(new OnClickListener()
			{
				@Override
				public void onClick(View v)
				{
					updateCurrentAction(diceAction);
					refresh();
					//toggleActionListContainer();
				}
			});
			diceActionIBtn.setOnLongClickListener(new OnLongClickListener()
			{
				@Override
				public boolean onLongClick(View v)
				{
					//openActionDialog();
					startActivity(new Intent(TZDice.this, ActionSetting.class));
					return true;
				}
			});
			
			actionListLayout.addView(diceActionIBtn);
		}
	}

	// Add listeners for button clicks
	private void setListeners()
	{
		rollBtn.setOnClickListener(this);
		//clearBtn.setOnClickListener(this);
		speakBtn.setOnClickListener(this);
		
		offsetPlusIBtn.setOnClickListener(this);
		offsetMinusIBtn.setOnClickListener(this);
		timesPlusIBtn.setOnClickListener(this);
		timesMinusIBtn.setOnClickListener(this);
		diceIBtn.setOnClickListener(this);
		offsetIBtn.setOnClickListener(this);
		timesIBtn.setOnClickListener(this);
		actionIBtn.setOnClickListener(this);
		shakeCtrlIBtn.setOnClickListener(this);
		userProfileIBtn.setOnClickListener(this);
		logIBtn.setOnClickListener(this);
		clearIBtn.setOnClickListener(this);
		
		offsetResultView.setOnClickListener(this);
		timesResultView.setOnClickListener(this);

		d4IView.setOnClickListener(this);
		d6IView.setOnClickListener(this);
		d8IView.setOnClickListener(this);
		d10IView.setOnClickListener(this);
		d12IView.setOnClickListener(this);
		d20IView.setOnClickListener(this);
		d100IView.setOnClickListener(this);

		d4IView.setOnLongClickListener(this);
		d6IView.setOnLongClickListener(this);
		d8IView.setOnLongClickListener(this);
		d10IView.setOnLongClickListener(this);
		d12IView.setOnLongClickListener(this);
		d20IView.setOnLongClickListener(this);
		d100IView.setOnLongClickListener(this);

		offsetPlusIBtn.setOnLongClickListener(this);
		offsetMinusIBtn.setOnLongClickListener(this);
		timesPlusIBtn.setOnLongClickListener(this);
		timesMinusIBtn.setOnLongClickListener(this);

		offsetIBtn.setOnLongClickListener(this);
		timesIBtn.setOnLongClickListener(this);
		diceIBtn.setOnLongClickListener(this);
		actionIBtn.setOnLongClickListener(this);
		
		rollBtn.setOnLongClickListener(this);
		speakBtn.setOnLongClickListener(this);

		micIView.setOnLongClickListener(this);
		
		offsetResultView.setOnLongClickListener(this);
		timesResultView.setOnLongClickListener(this);
		
		if( AccelerometerManager.isSupported(this))
		{
			AccelerometerManager.startListening(this, this);
			AccelerometerManager.configure(
					Setting.getShakeSensitivity(this), 
					TimeUtils.SECOND_OF_NANO
			);
		}
	}

	@Override
	public boolean onLongClick(View v)
	{
		// Toast.makeText(this, "Test", Toast.LENGTH_SHORT).show();
		switch (v.getId())
		{
			case R.id.d4_iv:
			case R.id.d6_iv:
			case R.id.d8_iv:
			case R.id.d10_iv:
			case R.id.d12_iv:
			case R.id.d20_iv:
			case R.id.d100_iv:
				selectDice(Integer.parseInt((String) v.getTag()));
				doRoll(currentAction);
				break;
			case R.id.dice_btn:
				selectDice(Setting.getDefaultDice(this));
				break;
			case R.id.action_offset_btn:
			case R.id.offset_result:
				currentAction.setOffset(Constants.DEFAULT_OFFSET);
				break;
			case R.id.times_btn:
			case R.id.times_result:
				currentAction.setTimes(Constants.DEFAULT_TIMES);
				break;
			case R.id.offset_plus_btn:
				currentAction.setOffset(Setting.getOffsetMaximum(this));
				break;
			case R.id.offset_minus_btn:
				currentAction.setOffset(Setting.getOffsetMinmum(this));
				break;
			case R.id.times_plus_btn:
				currentAction.setTimes(Setting.getTimesMaximum(this));
				break;
			case R.id.times_minus_btn:
				currentAction.setTimes(Constants.DEFAULT_TIMES);
				break;
			case R.id.action_btn:
				//startActivity(new Intent(this, ActionSetting.class));
				openActionDialog();
				break;
			case R.id.roll_btn:
				toggleRollContainer();
				Toast.makeText(this, R.string.tip_002, Toast.LENGTH_SHORT).show();
				break;
			case R.id.speak_btn:
				toggleSaycontainer();
				Toast.makeText(this, R.string.tip_001, Toast.LENGTH_SHORT).show();
				break;
			case R.id.voice_img:
				doRecordMic();
				break;
		}
		updateStatus();
		return true;
	}
	
	// Implements the OnClickListener
	public void onClick(View v)
	{
		switch (v.getId())
		{
			case R.id.roll_btn:
				doRoll(currentAction);
				break;
			case R.id.d4_iv:
			case R.id.d6_iv:
			case R.id.d8_iv:
			case R.id.d10_iv:
			case R.id.d12_iv:
			case R.id.d20_iv:
			case R.id.d100_iv:
				selectDice(Integer.parseInt((String) v.getTag()));
				break;
			case R.id.offset_plus_btn:
				setOffset(currentAction.getOffset() + 1);
				break;
			case R.id.offset_minus_btn:
				setOffset(currentAction.getOffset() - 1);
				break;
			case R.id.times_plus_btn:
				setTimes(currentAction.getTimes() + 1);
				break;
			case R.id.times_minus_btn:
				setTimes(currentAction.getTimes() - 1);
				break;
			case R.id.action_offset_btn:
				toggleOffsetContainer();
				break;
			case R.id.dice_btn:
				toggleDiceTable();
				break;
			case R.id.times_btn:
				toggleTimesContainer();
				break;
			case R.id.action_btn:
				if( actionManager.getActionNumber() == 0 )
				{
					startActivity(new Intent(this, ActionSetting.class));
				}
				else
				{
					toggleActionListContainer();
				}
				break;
			case R.id.clear_btn:
				clearRollResult();
				break;
			case R.id.offset_result:
				toggleOffsetContainer();
				break;
			case R.id.times_result:
				toggleTimesContainer();
				break;
			case R.id.shake_control_btn:
				switchShake();
				break;
			case R.id.user_profile_btn:
				openUserProfileScreen();
				break;
			case R.id.log_btn:
				openLogDialog();
				break;
			case R.id.speak_btn:
				doSay();
				break;
		}
		updateStatus();
	}

	private void switchShake()
	{
		Setting.setShake(this, !Setting.getShake(this));
		
		if( Setting.getShake(this))
		{
			shakeCtrlIBtn.setImageResource(R.drawable.shake_on);
			Toast.makeText(this, R.string.msg_function_shake_on, Toast.LENGTH_SHORT).show();;
		}
		else
		{
			shakeCtrlIBtn.setImageResource(R.drawable.shake_off);
			Toast.makeText(this, R.string.msg_function_shake_off, Toast.LENGTH_SHORT).show();
		}
	}

	public void setOffset(int offset)
	{
		currentAction.setOffset(offset);
		checkOffset();
	}

	public void setTimes(int times)
	{
		currentAction.setTimes(times);
		checkTimes();
	}

	public void selectAllDices(boolean selected)
	{
		if (selected)
		{
			d4IView.setAlpha(Constants.ALPHA_SELECTED);
			d6IView.setAlpha(Constants.ALPHA_SELECTED);
			d8IView.setAlpha(Constants.ALPHA_SELECTED);
			d10IView.setAlpha(Constants.ALPHA_SELECTED);
			d12IView.setAlpha(Constants.ALPHA_SELECTED);
			d20IView.setAlpha(Constants.ALPHA_SELECTED);
			d100IView.setAlpha(Constants.ALPHA_SELECTED);
		}
		else
		{
			d4IView.setAlpha(Constants.ALPHA_UNSELECTED);
			d6IView.setAlpha(Constants.ALPHA_UNSELECTED);
			d8IView.setAlpha(Constants.ALPHA_UNSELECTED);
			d10IView.setAlpha(Constants.ALPHA_UNSELECTED);
			d12IView.setAlpha(Constants.ALPHA_UNSELECTED);
			d20IView.setAlpha(Constants.ALPHA_UNSELECTED);
			d100IView.setAlpha(Constants.ALPHA_UNSELECTED);
		}
	}

	public void toggleViewsVisibility(View v, int invisibleOrGone)
	{
		int visibility;
		Animation fadeEffect = null;
		switch (v.getVisibility())
		{
			case View.VISIBLE:
				visibility = invisibleOrGone;	//fade in
				fadeEffect = AnimationUtils.loadAnimation(this, R.anim.fadeout);
				break;
			case View.INVISIBLE:
			case View.GONE:
				visibility = View.VISIBLE;	//fade out
				if( Setting.getAnimation(this))
				fadeEffect = AnimationUtils.loadAnimation(this, R.anim.fadein);
				break;
			default:
				return;
		}
		
		if( Setting.getAnimation(this))
		{
			v.startAnimation(fadeEffect);
		}
		v.setVisibility(visibility);
	}

	private void checkAndSetOtherContainerVisibility( int invisibleOrGone, View... otherViews)
	{
		for( View otherView : otherViews )
		{
			if (otherView.getVisibility() == View.VISIBLE)
			{
				otherView.setVisibility(invisibleOrGone);
			}
		}
	}

	private void toggleDiceTable()
	{
		toggleViewsVisibility(diceTable, View.GONE);
	}
	
	private void toggleRollContainer()
	{
		//checkAndSetOtherContainerVisibility(View.GONE, sayContainer);
		
		toggleViewsVisibility(rollContainer, View.GONE);
		toggleViewsVisibility(sayContainer, View.GONE);
	}
	
	private void toggleSaycontainer()
	{
		//checkAndSetOtherContainerVisibility(View.GONE, rollContainer);
		
		toggleViewsVisibility(sayContainer, View.GONE);
		toggleViewsVisibility(rollContainer, View.GONE);
	}
	
	private void toggleOffsetContainer()
	{
		checkAndSetOtherContainerVisibility(View.GONE, timesContainer, actionListContainer);
		toggleViewsVisibility(offsetContainer, View.GONE);
	}

	private void toggleTimesContainer()
	{
		checkAndSetOtherContainerVisibility(View.GONE, offsetContainer, actionListContainer);
		
		toggleViewsVisibility(timesContainer, View.GONE);
	}
	
	private void toggleActionListContainer()
	{
		checkAndSetOtherContainerVisibility(View.GONE, timesContainer, offsetContainer);
		toggleViewsVisibility(actionListContainer, View.GONE);
	}
	
	private void openUserProfileScreen()
	{
		Intent intent = new Intent(this, UserProfilePicGrid.class);
		startActivity(intent);
	}
	
	private void openLogDialog()
	{
		AlertDialog.Builder alert = new AlertDialog.Builder(this);
		
		alert.setIcon(R.drawable.log)
			.setTitle(R.string.logdialog_title)
			.setMessage(logBuffer.toString())
			.setPositiveButton(R.string.label_ok, null)
			.show();
	}

	private void openActionDialog()
	{
		// Set an EditText view to get user input
		final EditText input = new EditText(this);
		input.setText(currentAction.getName());
		
		AlertDialog.Builder alert = new AlertDialog.Builder(this);
		
		alert.setIcon(R.drawable.action)
			.setTitle(R.string.actiondialog_title)
			.setMessage(R.string.actiondialog_message)
			.setView(input)
			.setPositiveButton(R.string.label_ok, new DialogInterface.OnClickListener()
			{
				public void onClick(DialogInterface dialog, int whichButton)
				{
					currentAction.setName(input.getText().toString());
					updateStatus();
				}
			})
			.setNegativeButton(R.string.label_cancel, new DialogInterface.OnClickListener()
			{
				public void onClick(DialogInterface dialog, int whichButton)
				{
					// Canceled.
				}
			})
			.show();
	}

	private void selectDice(int number)
	{
		selectAllDices(false);
		switch (number)
		{
			case 4:
				d4IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
			case 6:
				d6IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
			case 8:
				d8IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
			case 10:
				d10IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
			case 12:
				d12IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
			case 20:
				d20IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
			case 100:
				d100IView.setAlpha(Constants.ALPHA_SELECTED);
				break;
		}
		currentAction.setDice(number);
	}

	private void clearRollResult()
	{
		recordAdapter.clearRecords();
	}
	
	private void updateStatus()
	{
		checkTimes();
		checkOffset();

		offsetResultView.setText(currentAction.getOffset() + "");
		timesResultView.setText(currentAction.getTimes() + "");
		
		setTitle(
			getResources().getString(R.string.app_name) + " " + 
			getResources().getString(R.string.app_version_name) + " - " +
			currentRecord.getUsername() + " " + currentAction.toString()
		);
	}

	private void checkTimes()
	{
		if (currentAction.getTimes() > Setting.getTimesMaximum(this))
		{
			currentAction.setTimes(Setting.getTimesMaximum(this));
		}
		else if (currentAction.getTimes() <= 0)
		{
			currentAction.setTimes(Constants.DEFAULT_TIMES);
		}
	}

	private void checkOffset()
	{
		if (currentAction.getOffset() > Setting.getOffsetMaximum(this))
		{
			currentAction.setOffset(Setting.getOffsetMaximum(this));
		}
		else if (currentAction.getOffset() < Setting.getOffsetMinmum(this))
		{
			currentAction.setOffset(Setting.getOffsetMinmum(this));
		}
	}
	
	private void doAnimation()
	{
		if(getCurrentDiceView() != null )
		{
			getCurrentDiceView().startAnimation(AnimationUtils.loadAnimation(this, R.anim.shake));
		}
	}
	
	private void doSoundEffect()
	{
		Music.play(this, R.raw.dice, false);
	}
	
	private void doRoll(DiceAction diceAction)
	{
		if ( Setting.getAnimation(this) )  doAnimation();
		if ( Setting.getSoundEffect(this) ) doSoundEffect();		
		
		DiceRecord newRecord = new DiceRecord(RecordType.Roll);
		newRecord.copy(currentRecord);
		newRecord.setType(RecordType.Roll);
		
		actionManager.generateDiceActionResult(diceAction, newRecord);
		
		recordAdapter.addRecord(newRecord);
		//TODO add time stamp in log
		logBuffer.append(newRecord.getContent()+"\n");
	}
	
	
	private static final int VOICE_RECOGNITION_REQUEST_CODE = 1234;
	
	private void doRecordMic()
	{
		// Check to see if a recognition activity is present
		PackageManager pm = getPackageManager();
		List<ResolveInfo> activities = pm.queryIntentActivities(new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH), 0);
		if (activities.size() != 0)
		{
			Intent intent = new Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH);
			intent.putExtra(RecognizerIntent.EXTRA_LANGUAGE_MODEL, RecognizerIntent.LANGUAGE_MODEL_FREE_FORM);
			intent.putExtra(RecognizerIntent.EXTRA_PROMPT, getResources().getText(R.string.recognizer_content));
			startActivityForResult(intent, VOICE_RECOGNITION_REQUEST_CODE);
		}
		else
		{
			Toast.makeText(this, getResources().getString(R.string.msg_rocognizer_not_present), Toast.LENGTH_SHORT).show();
		}
	}
	
	/**
	 * Handle the results from the recognition activity.
	 */
	@Override
	protected void onActivityResult(int requestCode, int resultCode, Intent data)
	{
		if (requestCode == VOICE_RECOGNITION_REQUEST_CODE && resultCode == RESULT_OK)
		{
			// Fill the list view with the strings the recognizer thought it could have heard
			ArrayList<String> matches = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS);
			StringBuffer voiceStr = new StringBuffer();
			for( String str : matches )
			{
				voiceStr.append(str);
			}
			
			sayET.setText(voiceStr);
		}

		super.onActivityResult(requestCode, resultCode, data);
	}
	
	private void doSay()
	{
		String sayStr = sayET.getText().toString();
		if(!StringUtils.isEmpty(sayStr))
		{
			DiceRecord newRecord = new DiceRecord(RecordType.Speak);
			newRecord.copy(currentRecord);
			
			newRecord.setType(RecordType.Speak);
			newRecord.setContent(sayStr);
			recordAdapter.addRecord(newRecord);
			logBuffer.append( currentRecord.getUsername() + ": " + sayStr + "\n");
		}
	}

	
	private void updateCurrentAction(DiceAction diceAction)
	{
		currentAction.copy(diceAction);
	}
	
	private View getCurrentDiceView()
	{
		switch(currentAction.getDice())
		{
			case 4:
				return d4IView;
			case 6:
				return d6IView;
			case 8:
				return d8IView;
			case 10:
				return d10IView;
			case 12:
				return d12IView;
			case 20:
				return d20IView;
			case 100:
				return d100IView;
		}
		
		return null;
	}

	@Override
	public void onAccelerationChanged(float x, float y, float z){}

	@Override
	public void onShake(float force)
	{
		if( Setting.getShake(this))
		{
			doRoll(currentAction);
		}
	}
}
